package com.ai.vita.redis.client;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import redis.clients.jedis.Jedis;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * redis客户端代理.
 */
public class RedisClient {

    private int dbNum;

    private int keyNum;

    private long valueNum;

    private RedisUtil redisUtil;

    public void setDbNum(int dbNum) {
        this.dbNum = dbNum;
    }

    public void setKeyNum(int keyNum) {
        this.keyNum = keyNum;
    }

    public void setValueNum(long valueNum) {
        this.valueNum = valueNum;
    }

    public void setRedisUtil(RedisUtil redisUtil) {
        this.redisUtil = redisUtil;
    }

    /**
     * 初始化连接池.
     * @param token
     * @param host
     * @return
     */
    public String init(String token, String... host){
        String ip, port = "6379", password = null;
        switch (host.length){
            case 1 :
                ip = host[0];
                break;
            case 2 :
                ip = host[0];
                port = host[1];
                break;
            case 3 :
            default:
                ip = host[0];
                port = host[1];
                password = host[2];
        }
        return redisUtil.init(token, ip, Integer.parseInt(port), password);
    }

    /**
     * 根据key获取value.
     * @param clientName
     * @param key
     * @return
     */
    public Map<String, String> getValue(String clientName, int dbIndex, String key){
        Map<String, String> returnMap = new HashMap<>();
        Jedis jedis = redisUtil.get(clientName);
        if(jedis != null){
            jedis.select(dbIndex);
            String type = jedis.type(key);
            switch (type){
                case "string" :
                    returnMap.put("value", jedis.get(key));
                    break;
                case "hash" :
                    Long size = jedis.hlen(key);
                    List<Map> valueList = new ArrayList<>();
                    if(size > valueNum){
                        size = valueNum;
                        String[] fields = jedis.hkeys(key).toArray(new String[0]);
                        for(int index = 0;index < size;index++){
                            String field = fields[index];
                            Map valueMap = new HashMap<>();
                            valueMap.put("key", field);
                            valueMap.put("value", jedis.hget(key, field));
                            valueList.add(valueMap);
                        }
                    }else{
                        Map<String, String> valueMap = jedis.hgetAll(key);
                        Iterator<String> fields = valueMap.keySet().iterator();
                        for (;fields.hasNext();) {
                            String field = fields.next();
                            String value = valueMap.get(field);
                            Map tMap = new HashMap();
                            tMap.put("key", field);
                            tMap.put("value", value);
                            valueList.add(tMap);
                        }
                    }
                    returnMap.put("value", JSONArray.fromObject(valueList).toString());
                    break;
                case "list" :
                    Long length = jedis.llen(key);
                    if(length > valueNum){
                        length = valueNum;
                    }else {
                        length = -1l;
                    }
                    List<String> value = jedis.lrange(key, 0, length);
                    returnMap.put("value", JSONArray.fromObject(value).toString());
                    break;
                case "set" :
                    Long setlen = jedis.scard(key);
                    if(setlen > valueNum){
                        setlen = valueNum;
                    }
                    Set<String> setValue = jedis.smembers(key);
                    String[] t = setValue.toArray(new String[]{});
                    Arrays.copyOfRange(t, 0, setlen.intValue());
                    returnMap.put("value", JSONArray.fromObject(t).toString());
                    break;
                case "zset" :
                    Long zsetlen = jedis.zcard(key);
                    if(zsetlen > valueNum){
                        zsetlen = valueNum;
                    }else {
                        zsetlen = -1l;
                    }
                    Set<String> zvalue = jedis.zrange(key, 0, zsetlen);
                    returnMap.put("value", JSONArray.fromObject(zvalue).toString());
                    break;
                default : returnMap.put("value", null);
            }
            returnMap.put("type", type);
        }
        return returnMap;
    }

    /**
     * 增加一个key.
     * @param clientName
     * @param key
     * @param valueType
     * @param value
     * @return
     */
    public boolean addKey(String clientName, int dbIndex, String key, String valueType, String value){
        Jedis jedis = redisUtil.get(clientName);
        if(jedis != null){
            jedis.select(dbIndex);
            switch (valueType){
                case "string":
                    jedis.set(key, value);
                    break;
                case "list" :
                    JSONArray listValues = JSONArray.fromObject(value);
                    Iterator<String> listIterator = listValues.iterator();
                    for (;listIterator.hasNext();) {
                        jedis.rpush(key, listIterator.next());
                    }
                    break;
                case "set" :
                    JSONArray setValues = JSONArray.fromObject(value);
                    Iterator<String> setIterator = setValues.iterator();
                    for (;setIterator.hasNext();) {
                        jedis.sadd(key, setIterator.next());
                    }
                    break;
                case "zset" :
                    JSONArray zsetValues = JSONArray.fromObject(value);
                    Iterator<String> zsetIterator = zsetValues.iterator();
                    int zsetScore = 0;
                    for (;zsetIterator.hasNext();) {
                        jedis.zadd(key, zsetScore++, zsetIterator.next());
                    }
                    break;
                case "hash" :
                    JSONArray hashValues = JSONArray.fromObject(value);
                    Iterator<JSONObject> hashIterator = hashValues.iterator();
                    for (;hashIterator.hasNext();) {
                        JSONObject obj = hashIterator.next();
                        jedis.hset(key, obj.getString("key"), obj.getString("value"));
                    }
                    break;
                default:
            }
        }
        return true;
    }

    /**
     * 获得dbs.
     * @param clientName
     * @return
     */
    public List getDbs(String clientName){
        Jedis jedis = redisUtil.get(clientName);
        List dbs = null;
        if(jedis != null){
            dbs = new ArrayList();
            for(int i = 0;i < dbNum; i++){
                try {
                    jedis.select(i);
                    String db = i + "," + jedis.dbSize();
                    dbs.add(db);
                }catch (Exception e){
                    break;
                }
            }
        }
        return dbs;
    }

    /**
     * 在所有db中查找key.
     * @param clientName
     * @param key
     * @return
     */
    public List queryKey(String clientName, String key){
        Jedis jedis = redisUtil.get(clientName);
        List<Map> dbs = null;
        if(jedis != null){
            key = "*" + key +"*";
            dbs = new ArrayList<>();
            for(int i = 0;i < dbNum; i++){
                try {
                    jedis.select(i);
                    Set keys = jedis.keys(key);
                    String db = i + "," + keys.size();
                    Map map = new HashMap();
                    map.put("db", db);
                    map.put("keys", keys);
                    dbs.add(map);
                }catch (Exception e){
                    break;
                }
            }
        }
        return dbs;
    }

    /**
     * 获取db里的所有key.
     * @param clientName
     * @param dbIndex
     * @return
     */
    public List getKeys(String clientName, int dbIndex){
        Jedis jedis = redisUtil.get(clientName);
        if(jedis != null){
            jedis.select(dbIndex);
            String[] keys = jedis.keys("*").toArray(new String[0]);
            if(keys.length > keyNum){
                keys = Arrays.copyOfRange(keys, 0, keyNum);
            }
            return Arrays.asList(keys);
        }else {
            return null;
        }
    }

    /**
     * 删除指定key.
     * @param clientName
     * @param dbIndex
     * @param key
     * @return
     */
    public boolean deleteKey(String clientName, int dbIndex, String key){
        Jedis jedis = redisUtil.get(clientName);
        if(jedis != null){
            jedis.select(dbIndex);
            jedis.del(key);
            return true;
        }else {
            return false;
        }
    }

    /**
     * 判断db中的key是否存在.
     * @param clientName
     * @param dbIndex
     * @param key
     * @return
     */
    public boolean existsKey(String clientName, int dbIndex, String key){
        Jedis jedis = redisUtil.get(clientName);
        if(jedis != null){
            jedis.select(dbIndex);
            return jedis.exists(key);
        }
        return false;
    }

}
